package com.example.online_gobang.api;

import com.example.online_gobang.game.MatchRequest;
import com.example.online_gobang.game.MatchResponse;
import com.example.online_gobang.game.Matcher;
import com.example.online_gobang.game.OnlineUserManager;
import com.example.online_gobang.model.User;
import com.example.online_gobang.tools.Constant;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 74646
 * Date: 2022-11-15
 * Time: 8:36
 */
// 通过这个类来处理匹配功能中的 websocket 请求
@Component
public class MatchAPI extends TextWebSocketHandler {
    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private OnlineUserManager onlineUserManager;

    @Autowired
    private Matcher matcher;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 玩家上线，加入到 OnlineUserManager 中

        // 1. 获取当前的用户信息（谁在游戏大厅创建连接）
        //    此处的代码, 之所以能够 getAttributes, 全靠了在注册 Websocket 的时候,
        //    加上的 .addInterceptors(new HttpSessionHandshakeInterceptor());
        //    这个逻辑就把 HttpSession 中的 Attribute 都给拿到 WebSocketSession 中了
        //    在 Http 登录逻辑中, 往 HttpSession 中存了 User 数据: httpSession.setAttribute("user", user);
        //    此时就可以在 WebSocketSession 中把之前 HttpSession 里存的 User 对象给拿到了.
        //    注意, 此处拿到的 user, 是有可能为空的!!
        //    如果之前用户压根就没有通过 HTTP 来进行登录, 直接就通过 /game_hall.html 这个 url 来访问游戏大厅页面
        //    此时就会出现 user 为 null 的情况
        User user = (User) session.getAttributes().get(Constant.USER_SESSION_KEY);

        // 2. 判断当前用户是否已经登录
        MatchResponse response = new MatchResponse();
        if (onlineUserManager.getFromGameHall(user.getUserId()) != null  || onlineUserManager.getFromGameRoom(user.getUserId()) != null) {
            // 当前用户已经登录
            response.setMessage("当前用户已经登录!");
            response.setStatus(-200);
            response.setReason("禁止游戏多开");
            /**
             *  先通过 ObjectMapper 把 MathResponse 对象转成 JSON 字符串
             *  然后再包装上一层 TextMessage,再进行传输
             *  TextMessage 就表示一个文本格式的 websocket 数据包
              */
            session.sendMessage(new TextMessage(objectMapper.writeValueAsBytes(response)));
            session.close();
            return;
        }

        // 3. 设置在线状态
        onlineUserManager.enterGameHall(user.getUserId(),session);
        System.out.println("玩家"+user.getUsername()+"进入游戏大厅");
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 处理开始匹配 和 停止匹配
        User user = (User) session.getAttributes().get(Constant.USER_SESSION_KEY);
        // 获取到客户端给服务器发送的数据
        String payload = message.getPayload();
        // 当前这个数据载荷是一个 JSON 格式的字符串，需要将它转换成 Java 对象（ MatchRequest )
        MatchRequest matchRequest = objectMapper.readValue(payload, MatchRequest.class); // 从客户端获取的数据
        MatchResponse matchResponse = new MatchResponse(); // 给客户端返回的数据
        if (matchRequest.getMessage().equals("startMatch")) {
            // 进入匹配队列
            // 创建匹配队列, 加入用户
            matcher.add(user);
            // 返回响应给前端
            matchResponse.setStatus(200);
            matchResponse.setMessage("startMatch");
        }else if(matchRequest.getMessage().equals("stopMatch")) {
            // 退出匹配队列
            // 创建匹配队列, 将用户移除
            matcher.remove(user);
            matchResponse.setMessage("stopMatch");
            matchResponse.setStatus(200);
        }else{
            // 非法情况
            matchResponse.setStatus(-200);
            matchRequest.setMessage("非法匹配");
        }
        session.sendMessage(new TextMessage(objectMapper.writeValueAsBytes(matchResponse)));
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        // 玩家异常下线，从 OnlineUserManager 中删除
        // 1. 获取用户信息
        User user = (User) session.getAttributes().get(Constant.USER_SESSION_KEY);
        WebSocketSession webSocketSession = onlineUserManager.getFromGameHall(user.getUserId());
        if(webSocketSession == session) {
            // 2. 设置离线状态
            onlineUserManager.exitGameHall(user.getUserId());
        }
        // 如果玩家正在匹配中，而 websocket 连接断开了就应该移除匹配队列
        matcher.remove(user);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        // 玩家正常下线，从 OnlineUserManager 中删除
        // 1. 获取用户信息
        User user = (User) session.getAttributes().get(Constant.USER_SESSION_KEY);
        WebSocketSession webSocketSession = onlineUserManager.getFromGameHall(user.getUserId());
        if(webSocketSession == session) {
            // 2. 设置在线状态
            onlineUserManager.exitGameHall(user.getUserId());
        }
        // 如果玩家正在匹配中，而 websocket 连接断开了就应该移除匹配队列
        matcher.remove(user);
    }
}
